package com.gitee.huanminabc.utils_tools.class_extend.javassist;

import com.gitee.huanminabc.jcommon.reflect.MethodUtil;
import com.gitee.huanminabc.jcommon.reflect.ReflectUtil;
import lombok.Data;
import lombok.SneakyThrows;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;

/**
 * 因为类一但被修改后, 就不能通过正常的方法访问对象内部的信息, 都需要通过反射的方式, 否则就会出现转换异常
 *
 * @author huanmin
 * @date 2024/2/26
 */
@Data
public class DynamicClass {
    private Class aClass;
    private Object newObj;
    /**
     * 动态创建对象
     *
     * @param aClass 需要创建的对象
     * @param args   构造参数
     */
    @SneakyThrows
    public DynamicClass(Class aClass, Object... args) {
        this.aClass = aClass;
        Class[] methodTypes = ReflectUtil.getObjectsToTypes(args);
        Constructor constructor = aClass.getConstructor(methodTypes);
        this.newObj = constructor.newInstance(args);
    }

    //执行方法
    @SneakyThrows
    public <R> R runMethod(String methodName, Object[] args, Class<R> returnType) {
        Class<?> aClass = ClassExtend.cl.findClass(this.aClass.getName());
        //因为类已经被改了,那么操作类的时候就不能将对象转换为类了,所以只能通过反射来获取类中的方法进行调用
        Class[] parameterTypes = ReflectUtil.getObjectsToTypes(args);
        Method test = aClass.getDeclaredMethod(methodName, parameterTypes);
        return (R) test.invoke(newObj, args);
    }

    //获取属性
    @SneakyThrows
    public <R> R getProperty(String propertyName, Class<R> returnType) {
        Class<?> aClass = ClassExtend.cl.findClass(this.aClass.getName());
        Field declaredField = aClass.getDeclaredField(propertyName);
        return (R) declaredField.get(newObj);
    }
    //获取方法注解
    @SneakyThrows
    public  <T extends Annotation>  T getMethodAnnotation(String methodName, Class<T>  annotation) {
        Class<?> aClass = ClassExtend.cl.findClass(this.aClass.getName());
        Method declaredMethod = aClass.getDeclaredMethod(methodName);
        return  declaredMethod.getAnnotation(annotation);
    }

    //获取类注解
    @SneakyThrows
    public  <T extends Annotation>  T getClassAnnotation(Class<T>  annotation) {
        Class<?> aClass = ClassExtend.cl.findClass(this.aClass.getName());
        return  aClass.getAnnotation(annotation);
    }
}
